package com.github.cakin.shiro.chapter21.web.controller;

import com.github.cakin.shiro.chapter21.entity.User;
import com.github.cakin.shiro.chapter21.service.UserRunAsService;
import com.github.cakin.shiro.chapter21.service.UserService;
import com.github.cakin.shiro.chapter21.web.bind.annotation.CurrentUser;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.util.List;

/**
 * @className: RunAsController
 * @description: 授予身份 / 回收身份 / 切换身份功能
 * @date: 2020/5/29
 * @author: cakin
 */
@Controller
@RequestMapping("/runas")
public class RunAsController {
    /**
     * 注入 userRunAsService
     */
    @Autowired
    private UserRunAsService userRunAsService;
    /**
     * 注入 userService
     */
    @Autowired
    private UserService userService;

    /**
     * 功能描述：返回当前登录用户的一些信息
     * 哪些用户可以给自己授权
     * 自己可以给哪些用户授权
     * 系统中除自己外的所有用户
     * 当前登录用户是否是Runas用户
     * 如果当前登录用户是Runas用户，被切之前的用户是哪位
     *
     * @param loginUser 登录用户
     * @param model 返回数据
     * @return String 展示页面
     * @author cakin
     * @date 2020/5/29
     */
    @RequestMapping
    public String runasList( @CurrentUser User loginUser, Model model ) {
        // 记录下哪些用户（老板）可以授权登录用户
        model.addAttribute("fromUserIds", userRunAsService.findFromUserIds(loginUser.getId()));
        // 记录登录用户可以给哪些用户（秘书）授权
        model.addAttribute("toUserIds", userRunAsService.findToUserIds(loginUser.getId()));

        List<User> allUsers = userService.findAll();
        allUsers.remove(loginUser);
        // 记录系统中除自己以为的所有用户
        model.addAttribute("allUsers", allUsers);
        // 获取当前主体
        Subject subject = SecurityUtils.getSubject();
        model.addAttribute("isRunas", subject.isRunAs());
        // 表示当前用户是否是 RunAs 用户，即已经切换身份了
        if (subject.isRunAs()) {
            // 得到切换身份之前的身份，一个用户可以切换很多次身份，之前的身份使用栈数据结构来存储
            String previousUsername = (String) subject.getPreviousPrincipals().getPrimaryPrincipal();
            // 记录切换前的身份
            model.addAttribute("previousUsername", previousUsername);
        }

        return "runas";
    }


    /**
     * 功能描述：登录者给toUserId授权
     * 把当前用户身份授予给另一个用户，这样另一个用户可以切换身份到该用户
     * @param loginUser          登录用户，比如老板
     * @param toUserId           被授权用户，比如秘书
     * @param redirectAttributes 重定向属性
     * @return String 重定向地址
     * @author cakin
     * @date 2020/5/29
     */
    @RequestMapping("/grant/{toUserId}")
    public String grant(
            @CurrentUser User loginUser,
            @PathVariable("toUserId") Long toUserId,
            RedirectAttributes redirectAttributes ) {
        // 不能给自己授权
        if (loginUser.getId().equals(toUserId)) {
            redirectAttributes.addFlashAttribute("msg", "自己不能切换到自己的身份");
            return "redirect:/runas";
        }
        // 登录者给toUserId授权
        userRunAsService.grantRunAs(loginUser.getId(), toUserId);
        redirectAttributes.addFlashAttribute("msg", "操作成功");
        return "redirect:/runas";
    }

    /**
     * 功能描述：登录者给toUserId取消授权
     * 把授予给某个用户的身份回收回来
     * @param loginUser          登录用户，比如老板
     * @param toUserId           被授权用户，比如秘书
     * @param redirectAttributes 重定向属性
     * @return String 重定向地址
     * @author cakin
     * @date 2020/5/29
     */
    @RequestMapping("/revoke/{toUserId}")
    public String revoke(
            @CurrentUser User loginUser,
            @PathVariable("toUserId") Long toUserId,
            RedirectAttributes redirectAttributes ) {
        userRunAsService.revokeRunAs(loginUser.getId(), toUserId);
        redirectAttributes.addFlashAttribute("msg", "操作成功");
        return "redirect:/runas";
    }

    /**
     * 功能描述：登录用户切换身份
     *
     * @param loginUser          登录用户，比方说 秘书
     * @param switchToUserId      切换后的用户 比方说 老板
     * @param redirectAttributes 重定向属性
     * @return switchToUserId 切换身份后的用户
     * @author cakin
     * @date 2020/5/29
     */
    @RequestMapping("/switchTo/{switchToUserId}")
    public String switchTo(
            @CurrentUser User loginUser,
            @PathVariable("switchToUserId") Long switchToUserId,
            RedirectAttributes redirectAttributes ) {
        // 获得当前主体
        Subject subject = SecurityUtils.getSubject();
        // 找到切换后的用户
        User switchToUser = userService.findOne(switchToUserId);
        // 自己不能给自己切换身份
        if (loginUser.equals(switchToUser)) {
            redirectAttributes.addFlashAttribute("msg", "自己不能切换到自己的身份");
            return "redirect:/runas";
        }
        // 被切换的身份不存在  或者  登录用户（秘书）有没有被 switchToUserId 用户（老板）授权
        if (switchToUser == null || !userRunAsService.exists(switchToUserId, loginUser.getId())) {
            redirectAttributes.addFlashAttribute("msg", "对方没有授予您身份，不能切换");
            return "redirect:/runas";
        }
        // 切换用户（秘书切老板身份）
        subject.runAs(new SimplePrincipalCollection(switchToUser.getUsername(), ""));
        redirectAttributes.addFlashAttribute("msg", "操作成功");
        redirectAttributes.addFlashAttribute("needRefresh", "true");
        return "redirect:/runas";
    }

    /**
     * 功能描述：切回身份 （从老板身份切回原来的 秘书身份）
     *
     * @param redirectAttributes 重定向属性
     * @return switchToUserId 切换身份后的用户
     * @author cakin
     * @date 2020/5/29
     */
    @RequestMapping("/switchBack")
    public String switchBack( RedirectAttributes redirectAttributes ) {
        // 获得主体
        Subject subject = SecurityUtils.getSubject();
        // 当前主体已经RunAs了
        if (subject.isRunAs()) {
            // 切换到原来用户（从老板身份切成秘书身份）
            subject.releaseRunAs();
        }
        redirectAttributes.addFlashAttribute("msg", "操作成功");
        redirectAttributes.addFlashAttribute("needRefresh", "true");
        return "redirect:/runas";
    }
}
